<?php
require_once './fun.php';
require_once './helper.php';

run();

function run()
{
    $data1 = click_view();
    $data2 = sessionId($data1['ip'], $data1['uuid']);
    $data3 = code_view($data2['sessionId']);
    $path  = down_image($data3['bgImgUrl'], $data3['puzzleImgUrl']);
    $data4 = valid_code($data3['responseId'], $data2['sessionId'], $path);
    $args  = [
        $data1['url'],
        $data1['uuid'],
        $data1['namespace'],
        $data2['sessionId'],
        $data4['successToken']
    ];
    $ret = continue_url(...$args);
    var_dump($ret);
}

function click_view()
{
    $url = 'http://callback.58.com/firewall/valid/988836761.do?namespace=chuzulistphp&url=nj.58.com%2Fchuzu%2F0%2F';
    $res = simple_curl($url)['content'];
    $pattern = '/<input type="hidden" id="(.*?)" value="(.*?)" \/>/i';
    $num = preg_match_all($pattern, $res, $matches);
    if ($num < 1) {
        die('click_view die');
    }
    return array_combine($matches[1], $matches[2]);
}

function sessionId($ip, $uuid)
{
    $time= time().'706';
    $url = "http://callback.58.com/firewall/code/{$ip}/{$uuid}.do?{$time}";
    $res = simple_curl($url)['content'];
    $data= json_decode($res, true);
    if ($data['code'] != 0) {
        die('sessionId die');
    }
    return $data['data'];
}

function code_view($sessionId)
{
    $url  = 'http://verifycode.58.com/captcha/getV3?';
    $time = time().'707';
    $args = [
        'callback'  => 'jQuery110108588881078363522_'.$time,
        'showType'  => 'win',
        'sessionId' => $sessionId,
        '_'         => $time
    ];
    $url  = $url.http_build_query($args);
    $resp = simple_curl($url)['content'];
    $data = substr($resp, strlen($args['callback']) + 1, -1);
    $data = json_decode($data, true);
    if ($data['code'] != 0) {
        die('code_view die');
    }
    return $data['data'];
}

function down_image($bgUrl, $puzzleUrl)
{
    $bgPath = __DIR__.'/images/big.jpeg';
    $puzPath= __DIR__.'/images/puzzle.png';
    $base   = 'http://verifycode.58.com';

    $ret = download_file($base.$bgUrl, $bgPath);
    if (empty($ret)) {
        die('down_image bg die');
    }
    $ret = download_file($base.$puzzleUrl, $puzPath);
    if (empty($ret)) {
        die('down_image puzzle die');
    }
    return [$bgPath, $puzPath];
}

function valid_code($responseId, $sessionId, $path)
{
    // 偏移量计算
    $x    = exec_img($path[0], $path[1]);
    $x    = round($x * 0.625) - 8;
    if ($x < 1) {
        die('验证图片识别错误!');
    }

var_dump($x, $responseId);
    $data = mcrypt_data($x, $responseId);
    $url  = 'http://verifycode.58.com/captcha/checkV3?';
    $time = time();
    $args = [
        'responseId' => $responseId,
        'sessionId'  => $sessionId,
        'data'       => $data,
    ];
    $url  = $url.http_build_query($args);
    $resp = simple_curl($url, null, ['Host: verifycode.58.com'])['content'];
    $data = json_decode($resp, true);
    var_dump($data);
    if (!array_key_exists('successToken', $data['data'])) {
        die('successToken 失败!'.PHP_EOL);
    }
    if ($data['code'] != 0) {
        die('successToken die!');
    }
    return $data['data'];
}

function continue_url($url, $uuid, $namespace, $sessionId, $successToken)
{
    $url = 'http://callback.58.com/firewall/valid/988836761.do?'
        ."namespace={$namespace}&url={$url}";
    $args= [
        'url'       => $url,
        'uuid'      => $uuid,
        'namespace' => $namespace,
        'sessionId' => $sessionId,
        'successToken'=>$successToken
    ];
    $resp = simple_curl($url, $args)['content'];
    $data = json_decode($resp, true);
    if ($data['code'] != 0) {
        die('continue_url die');
    }
    return $data['msg'];
}

function mcrypt_data($offsetX, $responseId)
{
    if ($offsetX > 240) $offsetX = 240;
    if ($offsetX < 0) $offsetX = 1;

    $track = track($offsetX);
    $data  = '{"x":"'.$offsetX.'","track":"'.$track.'","p":"0,0"}';
    $iv = $key = substr($responseId, 0, 16);
    $blocksize = @mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);  
    $len       = strlen($data);                    // 取得字符串长度
    $pad       = $blocksize - ($len % $blocksize); // 取得补码的长度
    $data     .= str_repeat(chr($pad), $pad);      // 用ASCII码为补码长度的字符,补足最后一段  
    $xcrypt    = @mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv); 
    $data      = strtoupper(bin2hex($xcrypt));
    return $data;
}

function mouse_move($xpos)
{
    $count = mt_rand(25, 68);

    $dict = 0; // 1 加速, 0 减速
    $time = 0; // 每个点的间隔时间
    $num  = 0; // 向上走多少个点
    $step = 1; // 步长
    $speed= 0;
    $moveX= mt_rand(21, 31);
    $moveY= 17;

    $trace = '';

    do {

        // init 减速为0的过程
        if (empty($num)) {
            $num = mt_rand(1, 5);
            $dict= ($count < 0) ? 0 : (!$dict);
        }

        // 速度X,匀速状态
        $step = 1;
        if (mt_rand(1,5) < 2)
            $step = 0;

        $temp = $step * ($dict?1:-1);
        if (($speed + $temp) < 0) $temp = -$speed;
        $speed += $temp;
        $moveX += min($speed, 5);
        $time  += mt_rand(15, 19);
        $xpos  -= $speed;
        if ($xpos <= 0) {
            $trace .= "{$moveX},{$moveY},{$time}|";
            break;
        }

        // 速度Y
        $temp = mt_rand() % 3;
        switch ($temp) {
            case 1: $moveY++; break;
            case 2: $moveY--; break;
        }

        $trace .= "{$moveX},{$moveY},{$time}|";

        --$num;
        --$count;
    } while (!($count <= 0 && !$num && !$dict && !$speed));

    return $trace;
}

function track($distance)
{
    # 移动轨迹
    $track = '';
    # 当前位移
    $current = 21;
    # 减速阈值
    $mid = $distance * 4 / 5;
    # 计算间隔
    $t = 0.2;
    # 初速度
    $v = 0;

    while ($current < $distance){
        if ($current < $mid) {
            # 加速度为正2
            $a = 2;
        } else {
            # 加速度为负3
            $a = -3;
        }

        // $t = mt_rand(17,);

        # 初速度v0
        $v0 = $v;
        # 当前速度v = v0 + at
        $v = $v0 + $a * $t;
        # 移动距离x = v0t + 1/2 * a * t^2
        $move = $v0 * $t + 1 / 2 * $a * $t * $t;
        # 当前位移
        $current += $move;
        # 加入轨迹
        $y = mt_rand(16, 19);
        $time = $y;
        $track .= intval($current).",$y,$time|";
    }
    return $track;
}